import sys
import rsa
from optparse import OptionParser
from rsa.loader.config_loader import ConfigLoader
from rsa.formatter.formatter import FormatterFactory
from rsa.util.common_utilities import parse_option
from rsa import rulesets
from rsa.export.export import ExporterFactory

# instance of the violation output formatter
formatter = None

def argument_parser():
    '''Returns a parser for command line options options'''
    parser = OptionParser(prog="rsa", description=__doc__)
    # create print options
    parser.add_option("-e", "--exclude", dest="exclude",
                      help="Specify the rules to exclude. This is a comma-separated list of rule names. Every rule listed will not be executed during the validation.")
    parser.add_option("-i", "--include", dest="include",
                      help="Specify the rules to include. This is a comma-separated list of rule names. Every rule listed will be executed during the validation.")
    parser.add_option("-q", "--quiet", dest="quiet", action="store_true",
                      help="This option turns the printing off")
    parser.add_option("-l", "--list", dest="listrules", action="store_true",
                      help="Prints the names of the rules imported by the system")
    parser.add_option("-d", "--describe", dest="describe",
                      help="Specify the rules to describe. This is a comma-separated list of rule names.")
    parser.add_option("-n", "--no-default", dest="nodefault", action="store_true",
                      help="Specify if the default rule sets should be loaded or not. Setting this option you are saying that the default rule sets should not be loaded in the system.")
    parser.add_option("-r", "--rulesetpath", dest="rulesetpath",
                      help="colon-separated list of directory and module " + 
                      "names used to search for rules. " + 
                      "(default=%s)" % ':'.join(rsa.RULESETPATH))
    parser.add_option("-f", "--format", dest="format",
                      help="Easily parseable output format. Formats supported: cvs, text")
    parser.add_option("-x", "--export", dest="export",
                      help="Export the violations found into a given file")    
    return parser

def  get_params(options):
    '''Parse the command line arguments'''
    # load preferences from configuration files
    (include, exclude, rsconfig) = ConfigLoader().load_preferences()
    # get the rules that should be loaded
    if(options.include):
        include = parse_option(options.include)
    # get the rules that shouldn't be loaded     
    if(options.exclude):
        exclude = parse_option(options.exclude)
    # set the rule set configuration
    rulesets.OPTIONS = rsconfig
    # get the path to the rule set definition files
    rulesetpath = None
    if(options.rulesetpath):
        rulesetpath = options.rulesetpath.split(":")
    if(not options.nodefault):
        if(rulesetpath):
            rulesetpath.append(rsa.RULESETPATH)
        else:
            rulesetpath = rsa.RULESETPATH
    return exclude, include, rulesetpath

def print_violation(state=None, violation=None):
    if state == "violation":
        if(formatter): print formatter.format(violation)

def print_errors_found(violations):    
    if(violations == 1):
        print str(violations) + " error found"
    else:
        print str(violations) + " errors found"
        
def print_useful_information():
    print "Robot Static Analyzer version " + rsa.__version__
    print "Copyright (c) 2011 Orbitz Worldwide"
    print "type 'rsa --help' for usage information."
    print
                
if __name__ == "__main__":
    # create and parse command line arguments
    parser = argument_parser()
    (options, args) = parser.parse_args(sys.argv)
    # if no arguments where given print useful information
    if(len(sys.argv) == 1):
        print_useful_information()
    # get the rule sets to load and ignored rules
    (exclude, include, rulesetpath) = get_params(options);
    rsa = rsa.RSA(rulesetpath)
    # if necessary print loaded rules
    if(options.describe):
        rsa.rule_set_factory.describe_rules(parse_option(options.describe))
    elif(options.listrules):
        rsa.rule_set_factory.list_rulesets()
    # get violation output formatter
    exporter = ExporterFactory().get_exporter(parse_option(options.format))
    formatter = FormatterFactory().get_formatter(parse_option(options.format))    
    # for each argument validate the source and if necessary print results
    violations = 0
    callback = None
    if not options.quiet: callback = print_violation
    for arg in args[1:]:
        report = rsa.validate(arg, callback=callback,ignore=exclude,use=include)
        if(not report): sys.exit(0)
        violations += len(report.violations)
        if(not options.quiet):
            print_errors_found(len(report.violations))
        if(options.export):
            report.validated_path = arg
            exporter.export_violations(report, parse_option(options.export))
    # exit system
    sys.exit(violations)
